package com.zhongjh.imageingstudy.view.clip;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.Log;

import androidx.annotation.ColorInt;

import com.zhongjh.imageingstudy.util.ImageUtils;


/**
 * 裁剪区域View
 * 该view是基于ActionImage的mClipFrame情况下的，所以该view的0,0也是基于mClipFrame的left,top
 */
public class ImageClipView implements ImageClip {

    private final String TAG = ImageClipView.class.getSimpleName();
    /**
     * 整个大窗口
     */
    public final RectF mWin = new RectF();
    /**
     * 裁剪窗口 - 高度缩小：height * VERTICAL_RATIO
     */
    private final RectF mWinFrame = new RectF();
    /**
     * 裁剪区域 - 当前裁剪区域,每次拖拽该区域都会随着改变
     */
    private final RectF mFrame = new RectF();
    /**
     * 归位区域 - 拖拽前的裁剪区域
     */
    private final RectF mHomingFrame = new RectF();


    private final float[] mCells = new float[16];

    private final float[] mCorners = new float[32];

    private final float[][] mBaseSizes = new float[2][4];

    /**
     * 是否在裁剪中
     */
    private boolean isClipping = false;
    /**
     * 是否在重置中
     */
    private boolean isResetting = true;
    /**
     * 是否在归位中
     */
    private boolean isHoming = false;

    /**
     * 用于处理缩放、旋转等操作
     */
    private final Matrix mMatrix = new Matrix();

    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    /**
     * 垂直窗口比例
     */
    private static final float VERTICAL_RATIO = 0.8f;

    private static final int COLOR_CELL = 0x80FFFFFF;

    private static final int COLOR_FRAME = Color.WHITE;

    private static final int COLOR_CORNER = Color.WHITE;

    private static final int COLOR_SHADE = 0xCC000000;

    {
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.SQUARE);
    }

    public ImageClipView() {

    }

    /**
     * 计算裁剪窗口区域
     */
    public void setClipWinSize(float width, float height) {
        Log.d(TAG, "setClipWinSize");
        mWin.set(0, 0, width, height);
        mWinFrame.set(0, 0, width, height * VERTICAL_RATIO);

        if (!mFrame.isEmpty()) {
            ImageUtils.center(mWinFrame, mFrame);
            Log.d(TAG, "setClipWinSize width: " + mFrame.width() + " height: " + mFrame.height());
            mHomingFrame.set(mFrame);
        }
    }

    /**
     * 重置/初始化裁剪的区域、角度
     */
    public void reset(RectF clipImage, float rotate) {
        Log.d(TAG, "reset");
        RectF imgRect = new RectF();
        mMatrix.setRotate(rotate, clipImage.centerX(), clipImage.centerY());
        mMatrix.mapRect(imgRect, clipImage);
        reset(imgRect.width(), imgRect.height());
    }

    /**
     * 重置裁剪
     */
    private void reset(float clipWidth, float clipHeight) {
        Log.d(TAG, "reset width: " + clipWidth + " height: " + clipHeight);
        setResetting(true);
        mFrame.set(0, 0, clipWidth, clipHeight);
        // 计算,将裁剪区域居中
        ImageUtils.fitCenter(mWinFrame, mFrame, CLIP_MARGIN);
        mHomingFrame.set(mFrame);
    }

    /**
     * 设置裁剪的归位区域
     */
    public void setHomingFrame() {
        Log.d(TAG, "setHomingFrame");
        mHomingFrame.set(mFrame);
        ImageUtils.fitCenter(mWinFrame, mHomingFrame, CLIP_MARGIN);
        // 如果不相等,则设置将要进行归位动画
        isHoming = !mHomingFrame.equals(mFrame);
    }

    /**
     * 设置裁剪的归位区域
     *
     * @param fraction 动画分
     */
    public void homing(float fraction) {
        Log.d(TAG, "homing");
        if (isHoming) {
            mFrame.set(
                    mFrame.left + (mHomingFrame.left - mFrame.left) * fraction,
                    mFrame.top + (mHomingFrame.top - mFrame.top) * fraction,
                    mFrame.right + (mHomingFrame.right - mFrame.right) * fraction,
                    mFrame.bottom + (mHomingFrame.bottom - mFrame.bottom) * fraction
            );
        }
    }

    public void onDraw(Canvas canvas) {
//        Log.d(TAG, "onDraw");
        if (isResetting) {
            return;
        }

        onDrawLine(canvas, mHomingFrame, Color.GREEN, 100);
        onDrawLine(canvas, mFrame, Color.YELLOW, 90);
//        onDrawLine(canvas, mWinFrame, Color.BLUE, 80);
//        onDrawLine(canvas, mWin, Color.WHITE, 70);

        float[] size = {mFrame.width(), mFrame.height()};
        for (int i = 0; i < mBaseSizes.length; i++) {
            for (int j = 0; j < mBaseSizes[i].length; j++) {
                mBaseSizes[i][j] = size[i] * CLIP_SIZE_RATIO[j];
            }
        }

        for (int i = 0; i < mCells.length; i++) {
            mCells[i] = mBaseSizes[i & 1][CLIP_CELL_STRIDES >>> (i << 1) & 3];
        }

        for (int i = 0; i < mCorners.length; i++) {
            mCorners[i] = mBaseSizes[i & 1][CLIP_CORNER_STRIDES >>> i & 1]
                    + CLIP_CORNER_SIZES[CLIP_CORNERS[i] & 3] + CLIP_CORNER_STEPS[CLIP_CORNERS[i] >> 2];
        }

        // 挪动位置再绘制
        canvas.translate(mFrame.left, mFrame.top);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(COLOR_CELL);
        mPaint.setStrokeWidth(CLIP_THICKNESS_CELL);
        canvas.drawLines(mCells, mPaint);

        // 挪动位置再绘制
        canvas.translate(-mFrame.left, -mFrame.top);
        mPaint.setColor(COLOR_FRAME);
        mPaint.setStrokeWidth(CLIP_THICKNESS_FRAME);
        canvas.drawRect(mFrame, mPaint);

        // 挪动位置再绘制
        canvas.translate(mFrame.left, mFrame.top);
        mPaint.setColor(COLOR_CORNER);
        mPaint.setStrokeWidth(CLIP_THICKNESS_SEWING);
        canvas.drawLines(mCorners, mPaint);
    }

    /**
     * 绘制参考线,开发用
     */
    private void onDrawLine(Canvas canvas, RectF frame, @ColorInt int color, int interval) {
        Paint paint = new Paint();
        paint.setColor(color);//颜色
        paint.setStrokeWidth(3);//线宽
        int verNum = (int) ((frame.bottom - frame.top) / interval) + 1;
        int horNum = (int) ((frame.right - frame.left) / interval) + 1;
        // 画横线
        for (int i = 0; i < verNum; i++) {
            canvas.drawLine(frame.left, frame.top + (i * interval - 1), frame.right, frame.top + (i * interval - 1), paint);
        }
        // 画竖线
        for (int i = 0; i < horNum; i++) {
            canvas.drawLine(frame.left + (i * interval - 1), frame.top, frame.left + (i * interval - 1), frame.bottom, paint);
        }
    }

    public Anchor getAnchor(float x, float y) {
        if (Anchor.isCohesionContains(mFrame, -CLIP_CORNER_SIZE, x, y)
                && !Anchor.isCohesionContains(mFrame, CLIP_CORNER_SIZE, x, y)) {
            int v = 0;
            float[] cohesion = Anchor.cohesion(mFrame, 0);
            float[] pos = {x, y};
            for (int i = 0; i < cohesion.length; i++) {
                if (Math.abs(cohesion[i] - pos[i >> 1]) < CLIP_CORNER_SIZE) {
                    v |= 1 << i;
                }
            }

            Anchor anchor = Anchor.valueOf(v);
            if (anchor != null) {
                isHoming = false;
            }
            return anchor;
        }
        return null;
    }

    public void onScroll(Anchor anchor, float dx, float dy) {
        anchor.move(mWinFrame, mFrame, dx, dy);
    }

    public boolean isHoming() {
        return isHoming;
    }

    public void setHoming(boolean homing) {
        isHoming = homing;
    }

    public boolean isClipping() {
        return isClipping;
    }

    public void setClipping(boolean clipping) {
        isClipping = clipping;
    }

    public boolean isResetting() {
        return isResetting;
    }

    public void setResetting(boolean resetting) {
        isResetting = resetting;
    }

    public RectF getFrame() {
        return mFrame;
    }

    public RectF getWinFrame() {
        return mWinFrame;
    }

    public RectF getOffsetFrame(float offsetX, float offsetY) {
        RectF frame = new RectF(mFrame);
        frame.offset(offsetX, offsetY);
        return frame;
    }

    public RectF getHomingFrame() {
        return mHomingFrame;
    }

    public RectF getOffsetTargetFrame(float offsetX, float offsetY) {
        RectF targetFrame = new RectF(mFrame);
        targetFrame.offset(offsetX, offsetY);
        return targetFrame;
    }
}
